<?php
namespace app\api\controller;

use app\common\controller\Api;
use think\Db;
use think\Log;
use think\Config;

/**
 * 回调接口
 * @ApiInternal
 */
class Notify extends Api
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = '*';
    
       /**
     * 处理微信商家转账回调通知
     * @return string
     */
    public function withdraw()
    {
        try {
            // 获取请求头信息
            $headers = array_change_key_case(getallheaders(), CASE_UPPER);
            // $timestamp = $headers['WECHATPAY-TIMESTAMP'];
            // $nonce = $headers['WECHATPAY-NONCE'];
            // $signature = $headers['WECHATPAY-SIGNATURE'];
            // $serial = $headers['WECHATPAY-SERIAL'];
            // Log::record('微信转账回调-请求头信息:', json_encode($headers, JSON_UNESCAPED_UNICODE));
            // 获取请求报文主体
            $body = file_get_contents('php://input');
            Log::record('微信转账回调-请求报文主体:', $body);
            // 验证签名
            $config = Config::get('wechat');
            // if (!$this->verifySignature($timestamp, $nonce, $body, $signature)) {
            //     Log::record('微信转账回调签名验证失败', 'error');
            //     return 'FAIL';
            // }
            
            // 解密回调数据
            $data = json_decode($body, true);
            $resource = $data['resource'];
            $ciphertext = $resource['ciphertext'];
            $associatedData = $resource['associated_data'];
            $nonceStr = $resource['nonce'];
            
            $decryptedData = $this->decryptResource($ciphertext, $nonceStr, $associatedData);
            if (!$decryptedData) {
                Log::record('微信转账回调数据解密失败', 'error');
                return 'FAIL';
            }
            Log::record('微信转账回调-解密后数据:', $decryptedData);
            // 处理转账状态
            $transferData = json_decode($decryptedData, true);
            $outBillNo = $transferData['out_bill_no'];
            $status = $transferData['state'];
            
            // 更新数据库中的转账状态
            switch ($status) {
                case 'PROCESSING':
                    $state = 'processing';
                    $msg = '转账处理中';
                    break;
                case 'SUCCESS':
                    $state = 'completed';
                    $msg = '转账成功';
                    break;
                case 'ACCEPTED':
                    $state = 'processing';
                    $msg = '单据已受理';
                    break;
                case 'CLOSED':
                    $state = 'closed';
                    $msg = '转账关闭';
                    break;
                case 'FAILED':
                    $state = 'fail';
                    $msg = $transferData['fail_reason'] ?? '转账失败';
                    break;
                default:
                    $state = 'unknown';
                    $msg = '未知状态';
            }
            
            // 更新提现记录状态
            Db::name('withdraw')->where('out_biz_no', $outBillNo)->update([
                'status' => $state,
                'updatetime' => time()
            ]);
            
            return 'SUCCESS';
            
        } catch (\think\exception\PDOException $e) {
            Log::record('处理微信转账回调异常：' . $e->getMessage(), 'error');
            return 'FAIL';
        }
    }
    
    /**
     * 验证回调签名
     */
    private function verifySignature($timestamp, $nonce, $body, $signature)
    {
        $config = Config::get('wechat');
        $message = $timestamp . "\n" . $nonce . "\n" . $body . "\n";
        $publicKey = openssl_get_publickey(file_get_contents(ROOT_PATH . $config['cert_path']));
        return openssl_verify(
            $message,
            base64_decode($signature),
            $publicKey,
            OPENSSL_ALGO_SHA256
        ) === 1;
    }
    
    /**
     * 解密回调资源数据
     */
    private function decryptResource($ciphertext, $nonce, $associatedData)
    {
        $config = Config::get('wechat');
        $key = $config['key'];
        $ciphertext = base64_decode($ciphertext);
        $ctext = substr($ciphertext, 0, -16);
        $authTag = substr($ciphertext, -16);
        $decrypted = openssl_decrypt(
            $ctext,
            'aes-256-gcm',
            $key,
            OPENSSL_RAW_DATA,
            $nonce,
            $authTag ,
            $associatedData
        );
        
        return $decrypted;
    }
    
}